﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using BASIC_CORE.Domain.Caching.Repositories;
using BASIC_CORE.Storage.Caching.DBContext;

namespace BASIC_CORE.Storage.Caching.Repositories
{
    /// <summary>
    /// 缓存服务仓储接口实现
    /// </summary>
    public class ServiceStackRedisCacheRepository : IServiceStackRedisCacheRepository
    {
        private RedisDbContext _redisDb;
        public ServiceStackRedisCacheRepository(RedisDbContext redisDbContext)
        {
            _redisDb = redisDbContext;
        }

        #region String 操作

        public async Task<string> GetString(string key)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetValue(key);
            return val;
        }

        public async Task SetString(string key, string value, int expirySeconds = -1)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            if (expirySeconds == -1)
            {
                redisClient.SetValue(key, value);
            }
            else
            {
                redisClient.SetValue(key, value, new TimeSpan(0, 0, 0, expirySeconds));
            }
        }

        public async Task SetString(string key, string value, TimeSpan? expireIn)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            if (expireIn == null)
            {
                redisClient.SetValue(key, value);
            }
            else
            {
                redisClient.SetValue(key, value, expireIn.Value);
            }
        }

        public async Task<bool> Remove(string key)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.Remove(key);
            return val;
        }

        public async Task RemoveAll(string[] keys)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.RemoveAll(keys);
        }

        #endregion String 操作

        #region Store-Object 操作

        public async Task<T> Store<T>(T entity) where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.Store(entity);
            return val;
        }

        public async Task StoreAll<T>(IEnumerable<T> entities) where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.StoreAll(entities);
        }

        public async Task<object> StoreObject(object entity)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.StoreObject(entity);
            return val;
        }

        public async Task<T> Get<T>(string key)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            return redisClient.Get<T>(key);
        }

        public async Task<T> GetById<T>(object id) where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetById<T>(id);
            return val;
        }

        public async Task<IList<T>> GetByIds<T>(ICollection ids) where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetByIds<T>(ids);
            return val;
        }

        public async Task<IList<T>> GetAll<T>() where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetAll<T>();
            return val;
        }

        public async Task<bool> AddIfNotExist<T>(string key, T entity, int expirySeconds = -1)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return expirySeconds == -1 ? redisClient.Add(key, entity) : redisClient.Add(key, entity, new TimeSpan(0, 0, 0, expirySeconds));
        }

        public async Task<bool> AddIfNotExist<T>(string key, T entity, TimeSpan? expireIn)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return expireIn == null ? redisClient.Add(key, entity) : redisClient.Add(key, entity, expireIn.Value);
        }

        public async Task Set<T>(string key, T entity, int expirySeconds = -1)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            if (expirySeconds == -1)
            {
                redisClient.Set(key, entity);
            }
            else
            {
                redisClient.Set(key, entity, new TimeSpan(0, 0, 0, expirySeconds));
            }
        }

        public async Task Set<T>(string key, T entity, TimeSpan? expireIn)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            if (expireIn == null)
            {
                redisClient.Set(key, entity);
            }
            else
            {
                redisClient.Set(key, entity, expireIn.Value);
            }
        }

        public async Task<bool> SetIfNotExists<T>(string key, T entity, int expirySeconds = -1)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return expirySeconds == -1 ? redisClient.Add(key, entity) : redisClient.Add(key, entity, new TimeSpan(0, 0, 0, expirySeconds));
        }

        public async Task<bool> SetIfNotExists<T>(string key, T entity, TimeSpan? expireIn)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return expireIn == null ? redisClient.Add(key, entity) : redisClient.Add(key, entity, expireIn.Value);
        }

        public async Task DeleteAll<T>() where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.DeleteAll<T>();
        }

        public async Task DeleteById<T>(object id) where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.DeleteById<T>(id);
        }

        public async Task DeleteByIds<T>(ICollection ids) where T : class, new()
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.DeleteByIds<T>(ids);
        }

        #endregion Store-Object 操作

        #region Hash-Store 操作

        public async Task StoreAsHash<T>(T entity)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.StoreAsHash(entity);
        }

        public async Task<T> GetFromHash<T>(object id)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetFromHash<T>(id);
            return val;
        }

        public async Task<int> GetHashCount(string hashId)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            return (int)redisClient.GetHashCount(hashId);
        }

        public async Task<List<string>> GetHashKeys(string hashId)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            return redisClient.GetHashKeys(hashId);
        }

        public async Task<List<string>> GetHashValues(string hashId)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            return redisClient.GetHashValues(hashId);
        }

        public async Task<string> GetValueFromHash(string hashId, string key)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetValueFromHash(hashId, key);
            return val;
        }

        public async Task<List<string>> GetValuesFromHash(string hashId, params string[] keys)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetValuesFromHash(hashId, keys);
            return val;
        }

        public async Task<Dictionary<string, string>> GetEntriesFromHash(string hashId)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            return redisClient.GetAllEntriesFromHash(hashId);
        }

        public async Task SetRangeInHash(string hashId, IEnumerable<KeyValuePair<string, string>> keyValuePairs)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.SetRangeInHash(hashId, keyValuePairs);
        }

        public async Task SetEntryInHash(string hashId, string key, string value)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.SetEntryInHash(hashId, key, value);
        }

        public async Task SetEntryInHashIfNotExists(string hashId, string key, string value)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.SetEntryInHashIfNotExists(hashId, key, value);
        }

        public async Task RemoveEntryFromHash(string hashId, string key)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.RemoveEntryFromHash(hashId, key);
        }

        #endregion Hash-Store 操作

        #region List操作

        public async Task<List<string>> GetAllItemsFromList(string key)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            return redisClient.GetAllItemsFromList(key);
        }

        public async Task AddItemToList(string key, string value)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.AddItemToList(key, value);
        }

        public async Task AddRangeToList(string key, List<string> values)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.AddRangeToList(key, values);
        }

        public async Task<string> DequeueItemFromList(string listId, int timeoutSeconds = -1)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return timeoutSeconds == -1 ? redisClient.DequeueItemFromList(listId) : redisClient.BlockingDequeueItemFromList(listId, new TimeSpan(0, 0, 0, timeoutSeconds));
        }

        public async Task<string> DequeueItemFromList(string listId, TimeSpan? timeOut = null)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return timeOut == null ? redisClient.DequeueItemFromList(listId) : redisClient.BlockingDequeueItemFromList(listId, timeOut);
        }

        public async Task EnqueueItemOnList(string listId, string value)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.EnqueueItemOnList(listId, value);
        }

        public async Task RemoveItemFromList(string listId, string value)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.RemoveItemFromList(listId, value);
        }

        #endregion List操作

        #region Inc-Dec 操作

        public async Task<long> IncrementValue(string key)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.IncrementValue(key);
            return val;
        }

        public async Task<long> IncrementValueBy(string key, int count)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.IncrementValueBy(key, count);
            return val;
        }

        public async Task<long> DecrementValue(string key)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.DecrementValue(key);
            return val;
        }

        public async Task<long> DecrementValueBy(string key, int count)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.DecrementValueBy(key, count);
            return val;
        }

        #endregion Inc-Dec 操作

        #region Other 操作

        public async Task<long> AppendToValue(string key, string value)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            var val = redisClient.AppendToValue(key, value);
            return val;
        }

        public async Task<string> GetRandomKey()
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetRandomKey();
            return val;
        }

        public async Task<List<string>> GetValues(List<string> keys)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetValues(keys);
            return val;
        }

        public async Task<List<T>> GetValues<T>(List<string> keys)
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.GetValues<T>(keys);
            return val;
        }

        public async Task<List<string>> GetAllKeys()
        {
            using var redisClient = await _redisDb.GetRedisClient(true);
            var val = redisClient.SearchKeys("*");
            return val;
        }

        public async Task SetAll(IEnumerable<string> keys, IEnumerable<string> values)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.SetAll(keys, values);
        }

        public async Task SetAll(Dictionary<string, string> map)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.SetAll(map);
        }

        public async Task<bool> Expire(string key, int seconds)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return redisClient.Expire(key, seconds);
        }

        public async Task<bool> ExpireAt(string key, long unixTime)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return redisClient.ExpireAt(key, unixTime);
        }

        public async Task<bool> ExpireEntryAt(string key, DateTime expireAt)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return redisClient.ExpireEntryAt(key, expireAt);
        }

        public async Task<bool> ExpireEntryIn(string key, TimeSpan expireIn)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            return redisClient.ExpireEntryIn(key, expireIn);
        }

        public async Task RemoveByPattern(string pattern)
        {
            using var redisClient = await _redisDb.GetRedisClient();
            redisClient.RemoveByPattern(pattern);
        }

        public async Task RemoveByRegex(string pattern)
        {
            await RemoveByPattern(pattern.Replace(".*", "*").Replace(".+", "?"));
        }

        #endregion Other 操作

    }
}
